﻿using Hangfire;
using Hangfire.States;
using Microsoft.Extensions.Logging;
using JESAI.Core.Aspects;
using JESAI.Core.Extensions;
using JESAI.Core.Util.Extensions.Strings;
using JESAI.Schedule.Hangfire.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using static System.Collections.Specialized.BitVector32;

namespace JESAI.Schedule.Hangfire.HandleCenter
{
   /// <summary>
   /// 任务调度处理
   /// </summary>
    public class ScheduleHandle
    {       
        private static IDictionary<string,Action<string>> _actionDict=new Dictionary<string, Action<string>>();

        public void StartJob(ScheduleOprions scheduleOprions)
        {         
            string queue = (scheduleOprions.Queue ?? "default").ToLower();

            if (queue.ToLower() == "systemqueue")
            {
                RecurringJob.AddOrUpdate(scheduleOprions.Id, () => ExecuteSystemQueueJob(scheduleOprions), scheduleOprions.Cron);
            }else if (queue.ToLower() == "bizqueue")
            {
                RecurringJob.AddOrUpdate(scheduleOprions.Id, () => ExecuteBizQueueJob(scheduleOprions), scheduleOprions.Cron);
            }
            else if (queue.ToLower() == "netqueue")
            {
                RecurringJob.AddOrUpdate(scheduleOprions.Id, () => ExecuteNetQueueJob(scheduleOprions), scheduleOprions.Cron);
            }
            else if (queue.ToLower() == "dataqueue")
            {
                RecurringJob.AddOrUpdate(scheduleOprions.Id, () => ExecuteDataQueueJob(scheduleOprions), scheduleOprions.Cron);
            }
            else 
            {
                RecurringJob.AddOrUpdate(scheduleOprions.Id, () => ExecuteJob(scheduleOprions), scheduleOprions.Cron);
            }
        }

        public void StopJob(string JobId)
        {
            _actionDict.Remove(JobId);
            RecurringJob.RemoveIfExists(JobId);
        }

        private Action<string> BuildInstance(ScheduleOprions scheduleOprions)
        {
            ILogger logger = ServiceLocator.Instance.GetServices<ILogger<ScheduleHandle>>().FirstOrDefault();
            
            string className = scheduleOprions.ClassName;
            string assemblyName = scheduleOprions.Assembly;
            string methodName = scheduleOprions.MethodName;
            if (assemblyName.IsNullOrEmptyOrWhiteSpace() || className.IsNullOrEmptyOrWhiteSpace() || methodName.IsNullOrEmptyOrWhiteSpace())
            {
                throw new Exception($"方法名:【MethodName】、程序集:【Assembly】、类名:【ClassName】全部不能为空，请检查是否有其中一个参数未配置!");
            }

            Assembly assembly = Assembly.Load(assemblyName);
            logger.LogInformation($"程序集名称{assemblyName}");
            Type type = assembly.GetType(className);

            if (type != null)
            {
                // 定义参数表达式
                ParameterExpression inputString = Expression.Parameter(typeof(string), "args");

                NewExpression newExpr = Expression.New(type);
                // 获取方法信息
                MethodInfo substringMethod = type.GetMethod(scheduleOprions.MethodName, new Type[] { typeof(string) });
                // 调用方法的表达式
                MethodCallExpression substringCall = Expression.Call(newExpr, substringMethod, inputString);
                // 编译表达式并调用
                Action<string> action = Expression.Lambda<Action<string>>(substringCall, inputString).Compile();
                logger.LogInformation($"{scheduleOprions.ClassName}创建实例完成!");
                return action;
            }
            else
            {
                throw new NotImplementedException("找不到类，无法调用!");
            }
        }

        public void ExecuteJob(ScheduleOprions scheduleOprions)
        {
            var _action = _actionDict.GetOrAdd(scheduleOprions.Id, () =>
            {
                return BuildInstance(scheduleOprions);
            });

            _action.Invoke(scheduleOprions.Args);
        }

        [Queue(queue:"systemqueue")]
        public void ExecuteSystemQueueJob(ScheduleOprions scheduleOprions)
        {
            var _action= _actionDict.GetOrAdd(scheduleOprions.Id, () =>
            {
                return BuildInstance(scheduleOprions); 
            });
          
            _action.Invoke(scheduleOprions.Args);
        }

        [Queue(queue: "bizqueue")]
        public void ExecuteBizQueueJob(ScheduleOprions scheduleOprions)
        {
            ILogger logger = ServiceLocator.Instance.GetServices<ILogger<ScheduleHandle>>().FirstOrDefault();
            logger.LogInformation($"{scheduleOprions.ClassName}定时任务执行!");
            var _action = _actionDict.GetOrAdd(scheduleOprions.Id, () =>
            {
                return BuildInstance(scheduleOprions);
            });

            _action.Invoke(scheduleOprions.Args);
        }

        [Queue(queue: "netqueue")]
        public void ExecuteNetQueueJob(ScheduleOprions scheduleOprions)
        {
            var _action = _actionDict.GetOrAdd(scheduleOprions.Id, () =>
            {
                return BuildInstance(scheduleOprions);
            });

            _action.Invoke(scheduleOprions.Args);
        }

        [Queue(queue: "dataqueue")]
        public void ExecuteDataQueueJob(ScheduleOprions scheduleOprions)
        {
            var _action = _actionDict.GetOrAdd(scheduleOprions.Id, () =>
            {
                return BuildInstance(scheduleOprions);
            });

            _action.Invoke(scheduleOprions.Args);
        }
    }
}
